/**
 *******************************************************************************
 * @file  hc32f160_pwc.c
 * @brief This file provides firmware functions to manage the Power Contorl(PWC).
 @verbatim
   Change Logs:
   Date             Author          Notes
   2020-11-27       CDT             First version
 @endverbatim
 *******************************************************************************
 * Copyright (C) 2020, Huada Semiconductor Co., Ltd. All rights reserved.
 *
 * This software component is licensed by HDSC under BSD 3-Clause license
 * (the "License"); You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at:
 *                    opensource.org/licenses/BSD-3-Clause
 *
 *******************************************************************************
 */

/*******************************************************************************
 * Include files
 ******************************************************************************/
#include "hc32f160_pwc.h"
#include "hc32f160_utility.h"

/**
 * @addtogroup HC32F160_DDL_Driver
 * @{
 */

/**
 * @defgroup DDL_PWC PWC
 * @brief Power Control Driver Library
 * @{
 */

#if (DDL_PWC_ENABLE == DDL_ON)

/*******************************************************************************
 * Local type definitions ('typedef')
 ******************************************************************************/

/*******************************************************************************
 * Local pre-processor symbols/macros ('#define')
 ******************************************************************************/
/**
 * @defgroup PWC_Local_Macros PWC Local Macros
 * @{
 */
#define PWC_LVD_MSK     (EFM_PWC_LVDICGCR_DFDIS | EFM_PWC_LVDICGCR_LVDLVL | \
                        EFM_PWC_LVDICGCR_NMIS | EFM_PWC_LVDICGCR_IRS)
/**
 * @defgroup PWC_Check_Parameters_Validity PWC Check Parameters Validity
 * @{
 */
/*  Check PWC register lock status. */
#define IS_PWC_UNLOCK()             ((CM_PWC->FPRC & PWC_FPRC_PWRWE) == PWC_FPRC_PWRWE)

/*  Check PWC LVD register lock status. */
#define IS_LVD_UNLOCK()             ((CM_PWC->FPRC & PWC_FPRC_LVRWE) == PWC_FPRC_LVRWE)

/*  Parameter validity check for stop mode high POR sel. */
#define IS_PWC_STOP_HIGH_PRECISION_POR(x)                                      \
(   ((x) == PWC_HIGH_PRECISION_POR_ON)          ||                             \
    ((x) == PWC_HIGH_PRECISION_POR_OFF))

/*  Parameter validity check for system clock sel while awake stop mode. */
#define IS_PWC_STOP_SYSCLK_AWAKE(x)                                            \
(   ((x) == PWC_SYSCLK_FIX)                     ||                             \
    ((x) == PWC_SYSCLK_HRCDIVX))

/*  Parameter validity check for wait flash while awake stop mode. */
#define IS_PWC_STOP_WAIT_FLASH_AWAKE(x)                                        \
(   ((x) == PWC_WAIT_FLASH_ON)                  ||                             \
    ((x) == PWC_WAIT_FLASH_OFF))

/*  Parameter validity check for power monitor sel. */
#define IS_PWC_MON_PWR_SEL(x)                                                  \
(   ((x) == PWC_MON_PWR_IREF)                   ||                             \
    ((x) == PWC_MON_PWR_TSENSOR))

/*  Parameter validity check for pwc dynamic voltage. */
#define IS_PWC_DYNAMIC_VOLTAGE(x)                                              \
(   ((x) == PWC_DYNAMIC_VOLTAGE_1P5V)           ||                             \
    ((x) == PWC_DYNAMIC_VOLTAGE_1P6V))

/*  Parameter validity check for LVD Level. */
#define IS_PWC_LVD_THRESHOLD_LEVEL(x)                                          \
(   ((x) == PWC_LVD_THRESHOLD_LEVEL0)           ||                             \
    ((x) == PWC_LVD_THRESHOLD_LEVEL1)           ||                             \
    ((x) == PWC_LVD_THRESHOLD_LEVEL2)           ||                             \
    ((x) == PWC_LVD_THRESHOLD_LEVEL3)           ||                             \
    ((x) == PWC_LVD_THRESHOLD_LEVEL4)           ||                             \
    ((x) == PWC_LVD_THRESHOLD_LEVEL5)           ||                             \
    ((x) == PWC_LVD_THRESHOLD_LEVEL6)           ||                             \
    ((x) == PWC_LVD_THRESHOLD_LEVEL7)           ||                             \
    ((x) == PWC_LVD_THRESHOLD_LEVEL8)           ||                             \
    ((x) == PWC_LVD_THRESHOLD_LEVEL9)           ||                             \
    ((x) == PWC_LVD_THRESHOLD_LEVEL10)          ||                             \
    ((x) == PWC_LVD_THRESHOLD_LEVEL11)          ||                             \
    ((x) == PWC_LVD_THRESHOLD_EXT_INPUT))

/*  Parameter validity check for LVD digital filter cycle selection. */
#define IS_PWC_LVD_DIG_FILTER_CLK(x)                                           \
(   ((x) == PWC_LVD_DIG_FILTER_CLK_2LRC)        ||                             \
    ((x) == PWC_LVD_DIG_FILTER_CLK_4LRC)        ||                             \
    ((x) == PWC_LVD_DIG_FILTER_CLK_8LRC)        ||                             \
    ((x) == PWC_LVD_DIG_FILTER_CLK_16LRC))

/*  Parameter validity check for PWC LVD exception type. */
#define IS_PWC_LVD_EXP_TYPE(x)                                                 \
(   ((x) == PWC_LVD_EXP_TYPE_INT)               ||                             \
    ((x) == PWC_LVD_EXP_TYPE_RST))

/*  Parameter validity check for PWC LVD interrupt mode. */
#define IS_PWC_LVD_INT_MD(x)                                                   \
(   ((x) == PWC_LVD_INT_MASK)                   ||                             \
    ((x) == PWC_LVD_INT_NONMASK))

/*  Parameter validity check for PWC LVD external input. */
#define IS_PWC_LVD_EXT_INPUT(x)                                                \
(   ((x) == PWC_LVD_EXT_INPUT_ON)           ||                             \
    ((x) == PWC_LVD_EXT_INPUT_OFF))

/*  Parameter validity check for PWC LVD digital filter. */
#define IS_PWC_DIG_LVD_FILTER(x)                                               \
(   ((x) == PWC_LVD_DIG_FILTER_ON)              ||                             \
    ((x) == PWC_LVD_DIG_FILTER_OFF))

/*  Parameter validity check for LVD flag. */
#define IS_PWC_LVD_FLAG(x)                                                     \
(   ((x) == PWC_LVD_FLAG_DET)                   ||                             \
    ((x) == PWC_LVD_FLAG_LVI))

/*  Parameter validity check for Ram protect area selection. */
#define IS_PWC_RAM_PROTECT_AREA_SEL(x)                                         \
(   ((x) == PWC_RAM_PROTECT_NONE)               ||                             \
    ((x) == PWC_RAM_PROTECT_128BYTE)            ||                             \
    ((x) == PWC_RAM_PROTECT_256BYTE)            ||                             \
    ((x) == PWC_RAM_PROTECT_512BYTE))

/**
 * @}
 */

/**
 * @}
 */

/*******************************************************************************
 * Global variable definitions (declared in header file with 'extern')
 ******************************************************************************/

/*******************************************************************************
 * Local function prototypes ('static')
 ******************************************************************************/

/*******************************************************************************
 * Local variable definitions ('static')
 ******************************************************************************/

/*******************************************************************************
 * Function implementation - global ('extern') and local ('static')
 ******************************************************************************/
/**
 * @defgroup PWC_Global_Functions PWC Global Functions
 * @{
 */

/**
 * @brief  Enter stop mode.
 * @param  None
 * @retval None
 */
void PWC_EnterStopMode(void)
{
    DDL_ASSERT(IS_PWC_UNLOCK());

    SET_REG8_BIT(CM_PWC->STPMCR, PWC_STPMCR_STOP);

     __WFI();
}

/**
 * @brief  Enter sleep mode.
 * @param  None
 * @retval None
 */
void PWC_EnterSleepMode(void)
{
    DDL_ASSERT(IS_PWC_UNLOCK());

    CLEAR_REG8_BIT(CM_PWC->STPMCR, PWC_STPMCR_STOP);

     __WFI();
}


/**
 * @brief  Power driver config when system switch high speed(>32KHz) to low speed(32KHz).
 * @param  None
 * @retval None
 * @note   The function can reduce power dissipation for system. The function
 *         should be called after system clock changed to low speed.
 */
void PWC_HighSpeedToLowSpeed(void)
{
    DDL_ASSERT(IS_PWC_UNLOCK());

    CLEAR_REG8_BIT(CM_PWC->PWRC, PWC_PWRC_PWDRV);

    /* Delay 30uS*/
    DDL_DelayUS(30UL);
}

/**
 * @brief  Power driver config when switch low speed(32KHz) to high speed(>32KHz).
 * @param  None
 * @retval None
 * @note   The function should be called before enter high speed mode.
 */
void PWC_LowSpeedToHighSpeed(void)
{
    DDL_ASSERT(IS_PWC_UNLOCK());

    SET_REG8_BIT(CM_PWC->PWRC, PWC_PWRC_PWDRV);

    /* Delay 30uS*/
    DDL_DelayUS(30UL);
}

/**
 * @brief  Init the stop config structure with default value.
 * @param  [in] pstcStopConfig      The pointer of stop config structure.
 *   @arg  u8HighPrecisionPOR : Specifies the high precision POR on or off while stop mode.
 *   @arg  u8SysClockMode     : Specifies the system clock while awake from stop mode.
 *   @arg  u8WaitFlash        : Specifies whether to wait flash stable while awake from stop mode.
 * @retval An en_result_t enumeration value:
 *   @arg  Ok                   : Initialize success
 *   @arg  ErrorInvalidParameter: Invalid parameter
 */
en_result_t PWC_StopStructInit(stc_pwc_stop_mode_t* pstcStopConfig)
{
    en_result_t enRet = Ok;

    /* Check if pointer is NULL */
    if (NULL == pstcStopConfig)
    {
        enRet = ErrorInvalidParameter;
    }
    else
    {
        /* Configure to default value */
        pstcStopConfig->u8HighPrecisionPOR = PWC_HIGH_PRECISION_POR_ON;
        pstcStopConfig->u8SysClockMode = PWC_SYSCLK_FIX;
        pstcStopConfig->u8WaitFlash = PWC_WAIT_FLASH_ON;
    }

    return enRet;
}

/**
 * @brief  Config the stop mode.
 * @param  [in] pstcStopConfig      The pointer of stop config.
 *   @arg  u8HighPrecisionPOR : Specifies the high precision POR on or off while stop mode.
 *   @arg  u8SysClockMode     : Specifies the system clock while awake from stop mode.
 *   @arg  u8WaitFlash        : Specifies whether to wait flash stable while awake from stop mode.
 * @retval An en_result_t enumeration value:
 *   @arg  Ok                   : Initialize success
 *   @arg  ErrorInvalidParameter: Invalid parameter
 * @retval None
 */
en_result_t PWC_StopModeConfig(const stc_pwc_stop_mode_t* pstcStopConfig)
{
    en_result_t enRet = Ok;

    if(pstcStopConfig == NULL)
    {
        enRet = ErrorInvalidParameter;
    }
    else
    {
        /* Parameter valid check */
        DDL_ASSERT(IS_PWC_STOP_HIGH_PRECISION_POR(pstcStopConfig->u8HighPrecisionPOR));
        DDL_ASSERT(IS_PWC_STOP_SYSCLK_AWAKE(pstcStopConfig->u8SysClockMode));
        DDL_ASSERT(IS_PWC_STOP_WAIT_FLASH_AWAKE(pstcStopConfig->u8WaitFlash));
        DDL_ASSERT(IS_PWC_UNLOCK());

        /* Config the stop mode */
        MODIFY_REG8(CM_PWC->STPMCR,                                               \
                    (PWC_STPMCR_HAPORDIS | PWC_STPMCR_CKSHRC | PWC_STPMCR_FLNWT), \
                    (pstcStopConfig->u8HighPrecisionPOR |                         \
                    pstcStopConfig->u8SysClockMode      |                         \
                    pstcStopConfig->u8WaitFlash));
    }

    return enRet;
}

/**
 * @brief  Set Dynamic voltage.
 * @param  [in] u8DynamicVoltage
 *   @arg  PWC_DYNAMIC_VOLTAGE_1P5V : VDD = 1.5V.
 *   @arg  PWC_DYNAMIC_VOLTAGE_1P6V : VDD = 1.6V.
 * @retval None.
 */
void PWC_SetDynamicVoltage(uint8_t u8DynamicVoltage)
{
    DDL_ASSERT(IS_PWC_DYNAMIC_VOLTAGE(u8DynamicVoltage));
    DDL_ASSERT(IS_PWC_UNLOCK());

    MODIFY_REG8(CM_PWC->PWRC, PWC_PWRC_DVS, u8DynamicVoltage);
}

/**
 * @brief  PWC Hrc LDO command.
 * @param  [in] enNewState
 *   @arg  Enable  : Enable the hrc LDO.
 *   @arg  Disable : Disable the hcr LDO.
 * @retval None
 */
void PWC_HrcLDOCmd(en_functional_state_t enNewState)
{
    DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
    DDL_ASSERT(IS_PWC_UNLOCK());

    if (Enable == enNewState)
    {
        WRITE_REG32(bCM_PWC->PWRC_b.VHRCE, 0UL);
    }
    else
    {
        WRITE_REG32(bCM_PWC->PWRC_b.VHRCE, 1UL);
    }
}

/**
 * @brief  Get PWC clock LDO status.
 * @param  None
 * @retval en_flag_status_t     Enumeration value:
 *   @arg  Set   : Hrc LDO is ready.
 *   @arg  Reset : Hrc LDO is not ready
 * @note   If enable Hrc, must wait 30us after hrc LDO ready.
 */
en_flag_status_t PWC_GetHrcLDOStatus(void)
{
    return ((0U != (READ_REG8_BIT(CM_PWC->PWRC, PWC_PWRC_HRCPWRDY)))? Set : Reset);
}

/**
 * @brief  PWC power monitor command.
 * @param  [in] enNewState
 *   @arg  Enable  : PWC power monitor enable.
 *   @arg  Disable : PWC power monitor disable.
 * @retval None
 * @note   This monitor power is used for ADC and output to REGC pin.
 */
void PWC_MonitorPowerCmd(en_functional_state_t enNewState)
{
    DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
    DDL_ASSERT(IS_PWC_UNLOCK());

    if(Enable == enNewState)
    {
        SET_REG8_BIT(CM_PWC->PWRMON, PWC_PWRMON_PWMONE);
    }
    else
    {
        CLEAR_REG8_BIT(CM_PWC->PWRMON, PWC_PWRMON_PWMONE);
    }
}

/**
 * @brief  PWC power monitor voltage config.
 * @param  [in] u8PowerSelect   PWC power monitor voltage config @ref PWC_Monitor_Power.
 *         This parameter can be one of the following values
 *   @arg  PWC_MON_PWR_IREF    : Monitor internal reference voltage of power supply
 *   @arg  PWC_MON_PWR_TSENSOR : Monitor temperature sensor voltage
 * @retval None
 * @note   This monitor power is used for ADC and output to REGC pin.
 */
void PWC_MonitorPwrSelect(uint8_t u8PowerSelect)
{
    DDL_ASSERT(IS_PWC_MON_PWR_SEL(u8PowerSelect));
    DDL_ASSERT(IS_PWC_UNLOCK());

    MODIFY_REG8(CM_PWC->PWRMON, PWC_PWRMON_PWMONSEL, u8PowerSelect);
}

/**
 * @brief  Init lvd config structure with default value.
 * @param  [in] pstcLvdInit         The pointer of lvd config structure.
 *   @arg  u16ExtInput         : Specifies external input on or off.
 *   @arg  u16ExceptionType    : Specifies the LVD exception type reset or interrupt.
 *   @arg  u16IntMode          : Specifies the LVD interrupt mode maskable or non_maskable.
 *   @arg  u16Filter           : Specifies the digital filter on or off.
 *   @arg  u16FilterClock      : Specifies the digital filter sample clock.
 *   @arg  u16ThresholdVoltage : Specifies the LVD threshold level.
 * @retval An en_result_t enumeration value:
 *   @arg  Ok: Initialize success
 *   @arg  ErrorInvalidParameter: Invalid parameter
 */
en_result_t PWC_LVD_StructInit(stc_pwc_lvd_init_t* pstcLvdInit)
{
    en_result_t enRet = Ok;

    /* Check if pointer is NULL */
    if (NULL == pstcLvdInit)
    {
        enRet = ErrorInvalidParameter;
    }
    else
    {
        /* Configure to default value */
        pstcLvdInit->u16ExtInput         = PWC_LVD_EXT_INPUT_OFF;
        pstcLvdInit->u16ExceptionType    = PWC_LVD_EXP_TYPE_INT;
        pstcLvdInit->u16IntMode          = PWC_LVD_INT_MASK;
        pstcLvdInit->u16Filter           = PWC_LVD_DIG_FILTER_ON;
        pstcLvdInit->u16FilterClock      = PWC_LVD_DIG_FILTER_CLK_2LRC;
        pstcLvdInit->u16ThresholdVoltage = PWC_LVD_THRESHOLD_LEVEL0;
    }

    return enRet;
}

/**
 * @brief  Config the Low Voltage Detector(LVD).
 * @param  [in] pstcLvdInit      The pointer of LVD config.
 *   @arg  u16ExtInput         : Specifies external input on or off.
 *   @arg  u16ExceptionType    : Specifies the LVD exception type reset or interrupt.
 *   @arg  u16IntMode          : Specifies the LVD interrupt mode maskable or non_maskable.
 *   @arg  u16Filter           : Specifies the digital filter on or off.
 *   @arg  u16FilterClock      : Specifies the digital filter sample clock.
 *   @arg  u16ThresholdVoltage : Specifies the LVD threshold level.
 * @retval An en_result_t enumeration value:
 *   @arg  Ok: Initialize success
 *   @arg  ErrorInvalidParameter: Invalid parameter
 */
en_result_t PWC_LVD_Init(const stc_pwc_lvd_init_t* pstcLvdInit)
{
    en_result_t enRet = Ok;

    if(pstcLvdInit == NULL)
    {
        enRet = ErrorInvalidParameter;
    }
    else
    {
        /* Parameter valid check */
        DDL_ASSERT(IS_PWC_LVD_EXT_INPUT(pstcLvdInit->u16ExtInput));
        DDL_ASSERT(IS_PWC_LVD_EXP_TYPE(pstcLvdInit->u16ExceptionType));
        DDL_ASSERT(IS_PWC_LVD_INT_MD(pstcLvdInit->u16IntMode));
        DDL_ASSERT(IS_PWC_DIG_LVD_FILTER(pstcLvdInit->u16Filter));
        DDL_ASSERT(IS_PWC_LVD_DIG_FILTER_CLK(pstcLvdInit->u16FilterClock));
        DDL_ASSERT(IS_PWC_LVD_THRESHOLD_LEVEL(pstcLvdInit->u16ThresholdVoltage));
        DDL_ASSERT(IS_LVD_UNLOCK());

        /* When modified pstcLvdInit->u16FilterClock, the pstcLvdInit->u16Filter shoule be PWC_LVD_DIG_FILTER_OFF
        LVDICGCR.DFS modified should when LVDICGCR.DFDIS = 1. */
        SET_REG16_BIT(CM_EFM->PWC_LVDICGCR, EFM_PWC_LVDICGCR_DFDIS);
        /* Set the LVD digital filter clock. */
        MODIFY_REG16(CM_EFM->PWC_LVDICGCR, EFM_PWC_LVDICGCR_DFS, pstcLvdInit->u16FilterClock);

        /* Config LVD. */
        MODIFY_REG16(CM_EFM->PWC_LVDICGCR, PWC_LVD_MSK,
                   (pstcLvdInit->u16Filter          | pstcLvdInit->u16ExtInput | \
                    pstcLvdInit->u16ExceptionType   | pstcLvdInit->u16IntMode  | \
                    pstcLvdInit->u16ThresholdVoltage));

        /* Config external intput */
        MODIFY_REG8(CM_PWC->LVDCSR, PWC_LVDCSR_EXVCCINEN, pstcLvdInit->u16ExtInput);
    }

    return enRet;
}

/**
 * @brief  Enable or disable the Low Voltage Detector(LVD).
 * @param  [in] enNewState      The new state of the LVD.
 *   @arg  This parameter can be: Enable or Disable.
 * @retval None
 */
void PWC_LVD_Cmd(en_functional_state_t enNewState)
{
    /* Parameter valid check */
    DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
    DDL_ASSERT(IS_LVD_UNLOCK());

    if (Enable == enNewState)
    {
        WRITE_REG32(bCM_EFM->PWC_LVDICGCR_b.LVDDIS, 0UL);
    }
    else
    {
        WRITE_REG32(bCM_EFM->PWC_LVDICGCR_b.LVDDIS, 1UL);
    }
}

/**
 * @brief  Enable or disable the LVD compare result output.
 * @param  [in] enNewState      The new state of the LVD CmpOutput.
 *   @arg  This parameter can be: Enable or Disable.
 * @note   This function should be call after PWC_LVD_Cmd(Enable), witch LVDICGCR.LVDDIS = 0.
 * @retval None
 */
void PWC_LVD_CompareOutputCmd(en_functional_state_t enNewState)
{
    /* Parameter valid check */
    DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
    DDL_ASSERT(IS_LVD_UNLOCK());

    WRITE_REG32(bCM_PWC->LVDCSR_b.CMPOE, enNewState);
}

/**
 * @brief  Enable or disable the external reference voltage.
 * @param  [in] enNewState      The new state of the LVD external reference voltage.
 *   @arg  This parameter can be: Enable or Disable.
 * @note   When enable, LVDICGCR.LVDLVL = b1110.
 * @retval None
 */
void PWC_LVD_ExtInputCmd(en_functional_state_t enNewState)
{
    /* Parameter valid check */
    DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
    DDL_ASSERT(IS_LVD_UNLOCK());

    WRITE_REG32(bCM_PWC->LVDCSR_b.EXVCCINEN, enNewState);
}

/**
 * @brief  Enable or disable the LVD exception.
 * @param  [in] enNewState      The new state of the LVD external reference voltage.
 *   @arg  This parameter can be: Enable or Disable.
 * @retval None
 */
void PWC_LVD_ExceptionCmd(en_functional_state_t enNewState)
{
    /* Parameter valid check */
    DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
    DDL_ASSERT(IS_LVD_UNLOCK());

    if (Enable == enNewState)
    {
        WRITE_REG32(bCM_EFM->PWC_LVDICGCR_b.IRDIS, 0UL);
    }
    else
    {
        WRITE_REG32(bCM_EFM->PWC_LVDICGCR_b.IRDIS, 1UL);
    }
}

/**
 * @brief  Enable or disable the LVD digital filter.
 * @param  [in] enNewState      The new state of the LVD external reference voltage.
 *   @arg  This parameter can be: Enable or Disable.
 * @retval None
 */
void PWC_LVD_DigitalFilterCmd(en_functional_state_t enNewState)
{
    /* Parameter valid check */
    DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
    DDL_ASSERT(IS_LVD_UNLOCK());

    if (Enable == enNewState)
    {
        WRITE_REG32(bCM_EFM->PWC_LVDICGCR_b.DFDIS, 0UL);
    }
    else
    {
        WRITE_REG32(bCM_EFM->PWC_LVDICGCR_b.DFDIS, 1UL);
    }
}

/**
 * @brief  Set LVD digital filter clock.
 * @param  [in] u16FilterClock  LVD filter clock. @ref PWC_LVD_Digital_Filter_Clock
 *   @arg  PWC_LVD_DIG_FILTER_CLK_2LRC : Filter clock is 2 LRC cycle.
 *   @arg  PWC_LVD_DIG_FILTER_CLK_4LRC : Filter clock is 4 LRC cycle.
 *   @arg  PWC_LVD_DIG_FILTER_CLK_8LRC : Filter clock is 8 LRC cycle.
 *   @arg  PWC_LVD_DIG_FILTER_CLK_16LRC: Filter clock is 16 LRC cycle.
 * @retval None
 */
void PWC_LVD_SetFilterClock( uint16_t u16FilterClock)
{
    /* Parameter valid check */
    DDL_ASSERT(IS_PWC_LVD_DIG_FILTER_CLK(u16FilterClock));
    DDL_ASSERT(IS_LVD_UNLOCK());

    MODIFY_REG16(CM_EFM->PWC_LVDICGCR, EFM_PWC_LVDICGCR_DFS, u16FilterClock);
}

/**
 * @brief  Select LVD exception type
 * @param  [in] u16ExceptionType    Interrupt or reset.
 *   @arg  PWC_LVD_EXP_TYPE_INT:    Select LVD interrupt.
 *   @arg  PWC_LVD_EXP_TYPE_RST:    Select LVD reset.
 * @retval None
 */
void PWC_LVD_SetExceptionType(uint16_t u16ExceptionType)
{
    DDL_ASSERT(IS_PWC_LVD_EXP_TYPE(u16ExceptionType));
    DDL_ASSERT(IS_LVD_UNLOCK());

    MODIFY_REG16(CM_EFM->PWC_LVDICGCR, EFM_PWC_LVDICGCR_IRS, u16ExceptionType);
}

/**
 * @brief  Set LVD threshold voltage.
 * @param  [in] u16VoltageThreshold     Compare voltage threshold
 *         This parameter can be one of the following values:
 *   @arg  PWC_LVD_THRESHOLD_LEVEL0   : LVD voltage threshold falling 3.92V and rising 4.07V.
 *   @arg  PWC_LVD_THRESHOLD_LEVEL1   : LVD voltage threshold falling 3.67V and rising 3.77V.
 *   @arg  PWC_LVD_THRESHOLD_LEVEL2   : LVD voltage threshold falling 3.06V and rising 3.15V.
 *   @arg  PWC_LVD_THRESHOLD_LEVEL3   : LVD voltage threshold falling 2.96V and rising 3.04V.
 *   @arg  PWC_LVD_THRESHOLD_LEVEL4   : LVD voltage threshold falling 2.86V and rising 2.94V.
 *   @arg  PWC_LVD_THRESHOLD_LEVEL5   : LVD voltage threshold falling 2.75V and rising 2.83V.
 *   @arg  PWC_LVD_THRESHOLD_LEVEL6   : LVD voltage threshold falling 2.65V and rising 2.73V.
 *   @arg  PWC_LVD_THRESHOLD_LEVEL7   : LVD voltage threshold falling 2.55V and rising 2.63V.
 *   @arg  PWC_LVD_THRESHOLD_LEVEL8   : LVD voltage threshold falling 2.45V and rising 2.52V.
 *   @arg  PWC_LVD_THRESHOLD_LEVEL9   : LVD voltage threshold falling 2.04V and rising 2.11V.
 *   @arg  PWC_LVD_THRESHOLD_LEVEL10  : LVD voltage threshold falling 1.94V and rising 2.00V.
 *   @arg  PWC_LVD_THRESHOLD_LEVEL11  : LVD voltage threshold falling 1.84V and rising 1.90V.
 *   @arg  PWC_LVD_THRESHOLD_EXT_INPUT: LVD use external input reference voltage.
 * @retval None
 * @note   If set PWC_LVD_THRESHOLD_EXT_INPUT, should call PWC_LVD_ExtInputCmd(Enable) to
 * enable external input.
 */
void PWC_LVD_SetVoltageThreshold(uint16_t u16VoltageThreshold)
{
    DDL_ASSERT(IS_PWC_LVD_THRESHOLD_LEVEL(u16VoltageThreshold));
    DDL_ASSERT(IS_LVD_UNLOCK());

    MODIFY_REG16(CM_EFM->PWC_LVDICGCR, EFM_PWC_LVDICGCR_LVDLVL, u16VoltageThreshold);
}

/**
 * @brief  Select LVD interrupt mode
 * @param  [in] u16IntMode    maskable or non_maskable.
 *   @arg  PWC_LVD_INT_MASK
 *   @arg  PWC_LVD_INT_NONMASK
 * @retval None
 */
void PWC_LVD_SetIntMode(uint16_t u16IntMode)
{
    DDL_ASSERT(IS_PWC_LVD_INT_MD(u16IntMode));
    DDL_ASSERT(IS_LVD_UNLOCK());

    MODIFY_REG16(CM_EFM->PWC_LVDICGCR, EFM_PWC_LVDICGCR_NMIS, u16IntMode);
}

/**
 * @brief  Get LVD flag.
 * @param  [in] u8Flag      The flag of LVD.
 *  This parameter can be one of the following values:
 *   @arg  PWC_LVD_FLAG_DET : VDD = VLVD or LVDINP = VInref
 *   @arg  PWC_LVD_FLAG_LVI : VCC < VLVD
 * @retval An en_flag_status_t enumeration value:
 *   @arg  Set  : LVD flag is set
 *   @arg  Reset: LVD flag is reset
 */
en_flag_status_t PWC_GetLvdFlag(uint8_t u8Flag)
{
    /* Parameter valid check */
    DDL_ASSERT(IS_PWC_LVD_FLAG(u8Flag));

    return ((0u == (CM_PWC->LVDCSR & u8Flag)) ? Reset :Set);
}

/**
 * @brief  Clear LVD flag.
 * @param  None
 * @retval None
 */
void PWC_ClearLvdDetectFlag(void)
{
    DDL_ASSERT(IS_PWC_UNLOCK());

    WRITE_REG32(bCM_PWC->LVDCSR_b.DETF, 0UL);
}

/**
 * @brief  PWC ram parity reset command.
 * @param  [in] enNewState
 *   @arg  Enable  : Enable reset while ram parity error.
 *   @arg  Disable : Disable reset while ram parity error.
 * @retval None
 */
void PWC_RamParityResetCmd(en_functional_state_t enNewState)
{
    DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
    DDL_ASSERT(IS_PWC_UNLOCK());

    if(Enable == enNewState)
    {
        CLEAR_REG8_BIT(CM_PWC->RAMCR, PWC_RAMCR_RPERDIS);
    }
    else
    {
        SET_REG8_BIT(CM_PWC->RAMCR, PWC_RAMCR_RPERDIS);
    }
}

/**
 * @brief  Configure Ram protect area.
 * @param  [in] u8ProtectArea       Ram protect area @ref PWC_RAM_protect_area.
 *         This parameter can be one of the following values
 *   @arg  PWC_RAM_PROTECT_NONE    : No protect.
 *   @arg  PWC_RAM_PROTECT_128BYTE : Ram start 128 bytes(0x20000000UL~0x20000080UL).
 *   @arg  PWC_RAM_PROTECT_256BYTE : Ram start 256 bytes(0x20000000UL~0x20000100UL).
 *   @arg  PWC_RAM_PROTECT_512BYTE : Ram start 512 bytes(0x20000000UL~0x20000200UL).
 * @retval None
 */
void PWC_RamProtectAreaConfig(uint8_t u8ProtectArea)
{
    DDL_ASSERT(IS_PWC_RAM_PROTECT_AREA_SEL(u8ProtectArea));
    DDL_ASSERT(IS_PWC_UNLOCK());

    MODIFY_REG8(CM_PWC->RAMCR, PWC_RAMCR_RPRTA, u8ProtectArea);
}

/**
 * @brief  Get the ram parity check flag.
 * @param  None
 * @retval An en_flag_status_t enumeration value:
 *   @arg  Set  : Ram parity flag is set.
 *   @arg  Reset: Ram parity flag is reset.
 */
en_flag_status_t PWC_GetRamParityStatus(void)
{
    return ((0U == (READ_REG8_BIT(CM_PWC->RAMCR, PWC_RAMCR_RPERF))) ? Reset : Set);
}

/**
 * @brief  Clear the ram parity check flag.
 * @param  None
 * @retval None
 */
void PWC_ClearRamParityStatus(void)
{
    DDL_ASSERT(IS_PWC_UNLOCK());

    WRITE_REG32(bCM_PWC->RAMCR_b.RPERF, 0UL);
}

/**
 * @brief  Enable or disable the Debug.
 * @param  [in] enNewState      The new state of the Debug.
 *   @arg  This parameter can be: Enable or Disable.
 * @retval None
 */
void PWC_DebugCmd(en_functional_state_t enNewState)
{
    /* Parameter valid check */
    DDL_ASSERT(IS_FUNCTIONAL_STATE(enNewState));
    DDL_ASSERT(IS_PWC_UNLOCK());

    WRITE_REG32(bCM_PWC->DBGC_b.DBGEN, enNewState);
}

/**
 * @}
 */

#endif  /* DDL_PWC_ENABLE */

/**
 * @}
 */

/**
* @}
*/

/******************************************************************************
 * EOF (not truncated)
 *****************************************************************************/
